#ifndef GLWIDGET_H
#define GLWIDGET_H

#include <QGLWidget>
#include <string>
#include <fstream>
#include <wchar.h>

#include "MatrixStack.h"
#include "window.h"
#include "..\Research2.0\Modeling\AlgeBSpline.h"

typedef struct {
    GLuint Projection;
    GLuint Modelview;
    GLuint NormalMatrix;
    GLuint LightPosition;
    GLuint AmbientMaterial;
    GLuint DiffuseMaterial;
    GLuint TessLevelInner;
    GLuint TessLevelOuter;
	GLuint NewtonParam;
} ShaderUniforms;

class GLWidget : public QGLWidget
{
    Q_OBJECT

public:
    GLWidget(QWidget *parent = 0);
    ~GLWidget();

    QSize minimumSizeHint() const;
    QSize sizeHint() const;
	void setWindowPointer(Window* window){pWindow = window;}
	void SetFPS();
	bool GetNeedGS(){return needGS;}
	bool GetInnerOuter(){return inOutToge;}
	void loadABSFile(LPCTSTR fileName);

public slots:
    void setXRotation(int angle);
    void setYRotation(int angle);
    void setZRotation(int angle);

	void setTessInner(int inner);
	void setTessOuter(int outer);
	void setIterNum(int iter);
	void setStepsize(int stepsize);
	void setEps(int ep);
	void setFuncScale(int fs);
	void setSubWire(bool need);
	void setInnOutFlag(bool need);


signals:
    void xRotationChanged(int angle);
    void yRotationChanged(int angle);
    void zRotationChanged(int angle);

	void setInnOut(int);

protected:
	//void paintEvent(QPaintEvent *event);
	void timerEvent( QTimerEvent *qte ) ;


    void initializeGL();
    void paintGL();
    void resizeGL(int width, int height);
    void mousePressEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);
	
	void computeFps();

	void EmptyIso(float* verts, int* faces);
	void multiple_knot_04(float* verts, int* faces);
	void fmd02_less(float* verts, int* faces);
	void createIcosahedron(float* verts, int* faces);
	void Tangle(float* verts, int* faces);
	void McMullenK3(float* verts, int* faces);
	void McMullenK3_21(float* verts, int* faces);
	void Schwartz(float* verts, int* faces);
	void TriCylinder(float* verts, int* faces);
	void BlobSchwartz(float* verts, int* faces);
	void DoubleTorus(float* verts, int* faces);
	void LemniscateOfGerono(float* verts, int* faces);

	void createInitIsosurface(float* verts, int* faces);
	void initIsosurface();
	void printShaderInfoLog(GLuint handle);
	void printProgramInfoLog(GLuint handle);
	//int loadShader(const std::string &fileName);

	void ChangeProgram(GLuint &progHandle);
	int CreateProgram(const std::string &fileName, GLuint &progHandle, bool need);
	int loadShaderFile(const std::string &fileName, const std::string &shaderExt, GLenum shaderType, GLuint &progHandle, GLuint &shaderHandle);


private:
    int xRot;
    int yRot;
    int zRot;	

    QPoint lastPos;
    QColor qtGreen;
    QColor qtPurple;

	std::ofstream fout;
	GLuint positions;
	GLuint indices;
	GLuint textureBuffer[2], textureData[2];
	GLuint positionSlot;
	GLuint normalSlot;
	int factNum;
	int vertNum;
	float TessLevelInner, TessLevelOuter;
	float nIter, stepSize, eps, funcScale;
	GLuint progHandleNo, progHandleGS;
	GLuint vsShader, tcsShader, tesShader, gsShader, fsShader, noGsfsShader;
	//ShaderUniforms uniforms;
	ModelViewMatrixStack modelViewMatrixStack;
	ProjectionMatrixStack projectionMatrixStack;
	
	ABSSf* pABS;
	Window* pWindow;
	int		realTimeID;
	bool	needVerticalSync;	
	bool	needGS;
	bool	inOutToge;	
};

#endif
